﻿/*************************************************************************************
   * CLR版本：       4.0.30319.42000
   * 类 名 称：       VlcPlayer
   * 机器名称：       ASUS-PC
   * 命名空间：       IPTVRClient.common
   * 文 件 名：       VlcPlayer
   * 创建时间：       2018/1/4 星期四 23:02:34
   * 作    者：          macui
   * 说   明：。。。。。
   * 修改时间：
   * 修 改 人：
  *************************************************************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.Security;
using IPTVRClient.Utils;
using IPTVRClient.utils;
using log4net;

namespace IPTVRClient.common
{
    class VlcPlayer
    {
        private IntPtr libvlc_instance_;
        private IntPtr libvlc_media_player_;

        ILog m_log = LogManager.GetLogger("VlcPlayer");

        /// <summary>
        /// 视频时长
        /// </summary>
        private int duration;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="pluginPath"></param>
        public VlcPlayer(string pluginPath, bool isH264)
        {
            try
            {
                string plugin_arg = "--plugin-path=" + pluginPath;

                if (isH264)
                {
                    //string[] arguments = { "-I", "dummy", "--ignore-config", "--no-video-title", "--demux=h264", "--network-caching=500", plugin_arg }; 
                    string tmpvlcarg = Global.configParam.SelfPara + ",-I,dummy,--ignore-config,--no-video-title,--plugin-path=" + pluginPath;
                    string[] arguments = tmpvlcarg.Split(',');
                    libvlc_instance_ = LibVlcAPI.libvlc_new(arguments);
                }
                else
                {
                    string tmparguments = "-I,dummy,--ignore-config,--no-video-title,--network-caching=100,--demux=rawaud,--rawaud-channels=" + Global.configParam.Channel + ",--rawaud-samplerate=" + Global.configParam.Rate + "," + plugin_arg;
                    string[] arguments = tmparguments.Split(',');
                    libvlc_instance_ = LibVlcAPI.libvlc_new(arguments);
                }

                if (libvlc_instance_ != IntPtr.Zero)
                {
                    libvlc_media_player_ = LibVlcAPI.libvlc_media_player_new(libvlc_instance_);
                }
            }
            catch(Exception ex)
            {
                m_log.Error("vlc创建异常，操作信息：" + ex.Message);
            }
        }

        /// <summary>
        /// 带参构造函数
        /// </summary>
        /// <param name="pluginPath"></param>
        /// <param name="vlcarg"></param>
        public VlcPlayer(string pluginPath, string vlcarg)
        {
            try
            {
                string tmpvlcarg = vlcarg + ",-I,dummy,--ignore-config,--no-video-title,--plugin-path=" + pluginPath;
                string[] arguments = tmpvlcarg.Split(',');

                libvlc_instance_ = LibVlcAPI.libvlc_new(arguments);
                if (libvlc_instance_ != IntPtr.Zero)
                {
                    libvlc_media_player_ = LibVlcAPI.libvlc_media_player_new(libvlc_instance_);
                }
            }
            catch (Exception ex)
            {
                m_log.Error("vlc创建异常，操作信息：" + ex.Message);
            }
        }

        /// <summary>
        /// 设置播放容器
        /// </summary>
        /// <param name="wndHandle">播放容器句柄</param>
        public void SetRenderWindow(int wndHandle)
        {
            try
            {
                if (libvlc_instance_ != IntPtr.Zero && wndHandle != 0)
                {
                    //m_log.Info("设置播放句柄");
                    LibVlcAPI.libvlc_media_player_set_hwnd(libvlc_media_player_, wndHandle);  //设置播放容器
                }
            }
            catch (Exception ex)
            {
                m_log.Error("设置播放容器，异常信息：" + ex.Message);
            }
        }

        /// <summary>
        /// 播放指定媒体文件
        /// </summary>
        /// <param name="filePath"></param>
        public void LoadFile(string filePath)
        {
            try
            {
                //m_log.Info("播放器加载本地文件，文件是" + filePath);
                IntPtr libvlc_media = LibVlcAPI.libvlc_media_new_path(libvlc_instance_, filePath);  //创建 libvlc_media_player 播放核心
                if (libvlc_media != IntPtr.Zero)
                {
                    LibVlcAPI.libvlc_media_parse(libvlc_media);
                    duration = (int)(LibVlcAPI.libvlc_media_get_duration(libvlc_media)/1000);  //获取视频时长

                    LibVlcAPI.libvlc_media_player_set_media(libvlc_media_player_, libvlc_media);  //将视频绑定到播放器去
                    LibVlcAPI.libvlc_media_release(libvlc_media);

                    // 自动播放
                    LibVlcAPI.libvlc_media_player_play(libvlc_media_player_);  //播放

                    //m_log.Info("播放文件");
                }
            }
            catch (Exception ex)
            {
                m_log.Error("播放本地文件异常，异常信息：" + ex.Message);
            }
        }
                
        /// <summary>
        /// 播放网络视频
        /// </summary>
        /// <param name="url"></param>
        public void LoadOnlineFile(string url)
        {
            try
            {
                IntPtr libvlc_media = LibVlcAPI.libvlc_media_new_location(libvlc_instance_, url);  //创建 libvlc_media_player 播放核心

                if (libvlc_media != IntPtr.Zero)
                {
                    LibVlcAPI.libvlc_media_parse(libvlc_media);
                    duration = (int)(LibVlcAPI.libvlc_media_get_duration(libvlc_media)/1000);  //获取视频时长

                    LibVlcAPI.libvlc_media_player_set_media(libvlc_media_player_, libvlc_media);  //将视频绑定到播放器去
                    LibVlcAPI.libvlc_media_release(libvlc_media);

                    // 自动播放
                    LibVlcAPI.libvlc_media_player_play(libvlc_media_player_);  //播放
                }
            }
            catch(Exception ex)
            {
                m_log.Error("播放远程文件异常，异常信息：" + ex.Message);
            }
        }
        
        public IntPtr GetAudioOutput()
        {
            return LibVlcAPI.libvlc_audio_output_list_get(libvlc_instance_);
        }

        /// <summary>
        /// 播放
        /// </summary>
        public void Play()
        {
            try
            {
                if (libvlc_media_player_ != IntPtr.Zero)
                {
                    LibVlcAPI.libvlc_media_player_play(libvlc_media_player_);
                }
            }
            catch (Exception ex)
            {
                m_log.Error("播放异常，异常信息：" + ex.Message);
            }
        }

        /// <summary>
        /// 暂停播放
        /// </summary>
        public void Pause()
        {
            try
            {
                if (libvlc_media_player_ != IntPtr.Zero)
                {
                    LibVlcAPI.libvlc_media_player_pause(libvlc_media_player_);
                }
            }
            catch (Exception ex)
            {
                m_log.Error("暂停播放异常，异常信息：" + ex.Message);
            }
        }

        /// <summary>
        /// 停止播放
        /// </summary>
        public void Stop()
        {
            try
            {
                if (libvlc_media_player_ != IntPtr.Zero)
                {
                    LibVlcAPI.libvlc_media_player_stop(libvlc_media_player_);
                }
            }
            catch (Exception ex)
            {
                m_log.Error("停止播放异常，异常信息：" + ex.Message);
            }
        }

       /// <summary>
       /// 
       /// </summary>
        public void Release()
        {
            if (libvlc_media_player_ != IntPtr.Zero)
            {
                LibVlcAPI.libvlc_media_release(libvlc_media_player_);
            }
        }

        /// <summary>
        /// 获取播放时间进度 ms
        /// </summary>
        /// <returns></returns>
        public int GetPlayTime()
        {
            return (int)(LibVlcAPI.libvlc_media_player_get_time(libvlc_media_player_)/1000);
        }

        /// <summary>
        /// 设置播放时间 ms
        /// </summary>
        /// <param name="seekTime"></param>
        public void SetPlayTime(double seekTime)
        {
            LibVlcAPI.libvlc_media_player_set_time(libvlc_media_player_, (Int64)(seekTime));
        }

        /// <summary>
        /// 获取音量
        /// </summary>
        /// <returns></returns>
        public int GetVolume()
        {
            return LibVlcAPI.libvlc_audio_get_volume(libvlc_media_player_);
        }

        /// <summary>
        /// 设置音量
        /// </summary>
        /// <param name="volume"></param>
        public void SetVolume(int volume)
        {
            LibVlcAPI.libvlc_audio_set_volume(libvlc_media_player_, volume);
        }

        /// <summary>
        /// 获取静音标志
        /// </summary>
        /// <returns></returns>
        public int GetMute()
        {
            return LibVlcAPI.libvlc_audio_get_mute(libvlc_media_player_);
        }
        
        /// <summary>
        /// 设置静音
        /// </summary>
        /// <param name="mute"></param>
        public void SetMute(bool istrue)
        {
            LibVlcAPI.libvlc_audio_set_mute(libvlc_media_player_, istrue ? 1 : 0);
        }

        /// <summary>
        /// 设置是否全屏
        /// </summary>
        /// <param name="istrue"></param>
        public void SetFullScreen(bool istrue)
        {
            LibVlcAPI.libvlc_set_fullscreen(libvlc_media_player_, istrue ? 1 : 0);
        }

        /// <summary>
        /// 视频时长
        /// </summary>
        /// <returns></returns>
        public int Duration()
        {
            if(duration == 0)
            {
                duration = (int)(LibVlcAPI.libvlc_media_player_get_length(libvlc_media_player_)/1000);
            }

            return duration;
        }


        /// <summary>
        /// 是否正在播放
        /// </summary>
        public bool IsPlaying(int time)
        {
            double tmpdur = Duration();
            double curpos = GetPlayTime();
            curpos = time > tmpdur ? tmpdur : curpos;

            if ((curpos < tmpdur /* 播放时间进度小于视频时长 */
                && tmpdur > 0 /* 播放时间进度大于0 */
               && curpos >= 0) || tmpdur == 0)
            {
                 return true;
            }
            else
            {
                 return false;
            }
        }
    }

    internal static class LibVlcAPI
    {
        /// <summary>
        /// 
        /// </summary>
        internal struct PointerToArrayOfPointerHelper
        {
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)]
            public IntPtr[] pointers;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="arguments"></param>
        /// <returns></returns>
        public static IntPtr libvlc_new(string[] arguments)
        {
            PointerToArrayOfPointerHelper argv = new PointerToArrayOfPointerHelper();
            argv.pointers = new IntPtr[11];
            for (int i = 0; i < arguments.Length; i++)
            {
                argv.pointers[i] = Marshal.StringToHGlobalAnsi(arguments[i]);
            }
            IntPtr argvPtr = IntPtr.Zero;
            try
            {
                int size = Marshal.SizeOf(typeof(PointerToArrayOfPointerHelper));
                argvPtr = Marshal.AllocHGlobal(size);
                Marshal.StructureToPtr(argv, argvPtr, false);
                return libvlc_new(arguments.Length, argvPtr);
            }
            finally
            {
                for (int i = 0; i < arguments.Length + 1; i++)
                {
                    if (argv.pointers[i] != IntPtr.Zero)
                    {
                        Marshal.FreeHGlobal(argv.pointers[i]);
                    }
                }
                if (argvPtr != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(argvPtr);
                }
            }
        }

        /// <summary>
        /// 创建vlc实例
        /// </summary>
        /// <param name="libvlc_instance"></param>
        /// <param name="path"></param>
        /// <returns></returns>
        public static IntPtr libvlc_media_new_path(IntPtr libvlc_instance, string path)
        {
            IntPtr pMrl = IntPtr.Zero;
            try
            {
                byte[] bytes = Encoding.UTF8.GetBytes(path);
                pMrl = Marshal.AllocHGlobal(bytes.Length + 1);
                Marshal.Copy(bytes, 0, pMrl, bytes.Length);
                Marshal.WriteByte(pMrl, bytes.Length, 0);
                return libvlc_media_new_path(libvlc_instance, pMrl);
            }
            finally
            {
                if (pMrl != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(pMrl);
                }
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="libvlc_instance"></param>
        /// <param name="path"></param>
        /// <returns></returns>
        public static IntPtr libvlc_media_new_location(IntPtr libvlc_instance, string path)
        {
            IntPtr pMrl = IntPtr.Zero;
            try
            {
                byte[] bytes = Encoding.UTF8.GetBytes(path);
                pMrl = Marshal.AllocHGlobal(bytes.Length + 1);
                Marshal.Copy(bytes, 0, pMrl, bytes.Length);
                Marshal.WriteByte(pMrl, bytes.Length, 0);
                return libvlc_media_new_location(libvlc_instance, pMrl);
            }
            finally
            {
                if (pMrl != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(pMrl);
                }
            }
        }

      
        // ----------------------------------------------------------------------------------------  
        // 以下是libvlc.dll导出函数  

        // 创建一个libvlc实例，它是引用计数的  
        [DllImport(@"libvlc.dll", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        private static extern IntPtr libvlc_new(int argc, IntPtr argv);

        // 释放libvlc实例  
        [DllImport(@"libvlc.dll", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern void libvlc_release(IntPtr libvlc_instance);

        [DllImport(@"libvlc.dll", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern String libvlc_get_version();

        // 从视频来源(例如Url)构建一个libvlc_meida  
        [DllImport(@"libvlc.dll", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        private static extern IntPtr libvlc_media_new_location(IntPtr libvlc_instance, IntPtr path);

        // 获取声卡列表
        [DllImport(@"libvlc.dll", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern IntPtr libvlc_audio_output_list_get(IntPtr libvlc_instance);

        // 设置声卡
        [DllImport(@"libvlc.dll", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        private static extern IntPtr libvlc_audio_output_set(IntPtr libvlc_media_player, string name);

        // 从本地文件路径构建一个libvlc_media  
        [DllImport(@"libvlc.dll", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        private static extern IntPtr libvlc_media_new_path(IntPtr libvlc_instance, IntPtr path);

        [DllImport(@"libvlc.dll", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern void libvlc_media_release(IntPtr libvlc_media_inst);

        // 创建libvlc_media_player(播放核心)  
        [DllImport(@"libvlc.dll", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern IntPtr libvlc_media_player_new(IntPtr libvlc_instance);

        // 将视频(libvlc_media)绑定到播放器上  
        [DllImport(@"libvlc.dll", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern void libvlc_media_player_set_media(IntPtr libvlc_media_player, IntPtr libvlc_media);

        // 设置图像输出的窗口  
        [DllImport(@"libvlc.dll", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern void libvlc_media_player_set_hwnd(IntPtr libvlc_mediaplayer, Int32 drawable);

        [DllImport(@"libvlc.dll", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern void libvlc_media_player_play(IntPtr libvlc_mediaplayer);

        /// <summary>  
        ///   
        /// </summary>  
        /// <param name="libvlc_mediaplayer"></param>  
        //[DllImport("libvlc", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]  
        //[SuppressUnmanagedCodeSecurity]  
        // public static extern void libvlc_media_player_fastforward(IntPtr libvlc_mediaplayer);  

        [DllImport(@"libvlc.dll", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern void libvlc_media_player_pause(IntPtr libvlc_mediaplayer);

        [DllImport(@"libvlc.dll", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern void libvlc_media_player_stop(IntPtr libvlc_mediaplayer);

        // 解析视频资源的媒体信息(如时长等)  
        [DllImport(@"libvlc.dll", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern void libvlc_media_parse(IntPtr libvlc_media);

        // 返回视频的时长(必须先调用libvlc_media_parse之后，该函数才会生效)  
        [DllImport(@"libvlc.dll", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern Int64 libvlc_media_get_duration(IntPtr libvlc_media);

        // 当前播放的时间  
        [DllImport(@"libvlc.dll", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern Int64 libvlc_media_player_get_time(IntPtr libvlc_mediaplayer);

        // 获取文件总时长 
        [DllImport(@"libvlc.dll", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern Int64 libvlc_media_player_get_length(IntPtr libvlc_mediaplayer);


        // 设置播放位置(拖动)  
        [DllImport(@"libvlc.dll", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern void libvlc_media_player_set_time(IntPtr libvlc_mediaplayer, Int64 time);

        [DllImport(@"libvlc.dll", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern void libvlc_media_player_release(IntPtr libvlc_mediaplayer);

        // 获取和设置音量  
        [DllImport(@"libvlc.dll", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern int libvlc_audio_get_volume(IntPtr libvlc_media_player);

        [DllImport(@"libvlc.dll", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern void libvlc_audio_set_volume(IntPtr libvlc_media_player, int volume);

        // 获取静音标志  
        [DllImport(@"libvlc.dll", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern int libvlc_audio_get_mute(IntPtr libvlc_media_player);

        // 设置静音
        [DllImport(@"libvlc.dll", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern void libvlc_audio_set_mute(IntPtr libvlc_media_player, int mute);

        // 设置全屏  
        [DllImport(@"libvlc.dll", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        public static extern void libvlc_set_fullscreen(IntPtr libvlc_media_player, int isFullScreen);
        
    }
}
